﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using OA.Infrastructure.Authentication;

namespace OA.Infrastructure.Impl;

internal class AccountService : IAccountService
{
    private readonly HttpClient _client;
    private readonly CredentialsOptions _credentialsOptions;
    private readonly IAuthenticationSchemeProvider _schemeProvider;

    private readonly IUserService _userService;

    public AccountService(
        OAuthEndpointService endpointService,
        IOptions<CredentialsOptions> credentialsOptions,
        IAuthenticationSchemeProvider schemeProvider,
        IUserService userService)
    {
        _client = endpointService.GetHttpClient();
        _credentialsOptions = credentialsOptions.Value;
        _schemeProvider = schemeProvider;
        _userService = userService;
    }

    public async Task<OperationalResult<LoginResult>> LoginAsync(LoginInfo loginInfo, CancellationToken cancellationToken = default)
    {
        var result = new OperationalResult<LoginResult>();

        var content = BuildPasswordMode(loginInfo.Account, loginInfo.Password, _credentialsOptions.Scope);

        var tokenEndpoint = "http://localhost:80/connect/token";
#if DEBUG        
        if (!App.ManagedByDocker)
        {
            var httpContext = App.HttpContext;

            if (httpContext is not null)
            {
                //var disco = await _client.GetDiscoveryDocumentAsync($"{httpContext.Request.Scheme}://{httpContext.Request.Host}{httpContext.Request.PathBase}", cancellationToken);
                tokenEndpoint = $"{httpContext.Request.Scheme}://{httpContext.Request.Host}{httpContext.Request.PathBase}/connect/token";
                //tokenEndpoint = disco.TokenEndpoint;
            }
        }
#endif

        var response = await _client.PostAsync(tokenEndpoint, content, cancellationToken);

        var loginResponse = await response.Content.ReadAsStringAsync(cancellationToken: cancellationToken);
        var jsonObj = JObject.Parse(loginResponse);

        var error = jsonObj.Value<string>("error");

        if (!string.IsNullOrWhiteSpace(error))
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }
        else
        {
            var userResult = await _userService.GetUserInfoAsync(loginInfo.Account, cancellationToken);
            await _userService.LoginAsync(loginInfo.Account, cancellationToken);

            result.Data = new LoginResult
            {
                Success = true,
                AccessToken = jsonObj.Value<string>("access_token"),
                Name = userResult.Data.Name,
                Avatar = userResult.Data.Avatar,
                QrCode = userResult.Data.QrCode
            };

            return result;
        }
    }

    private static FormUrlEncodedContent BuildPasswordMode(string username, string password, string? scope = null)
    {
        var data = PasswordData(username, password, scope);

        return new FormUrlEncodedContent(data);
    }

    private static IEnumerable<KeyValuePair<string, string>> PasswordData(string username, string password, string? scope = null)
    {
        return new Dictionary<string, string>
        {
            { "grant_type", "password" },
            { "username", username },
            { "password", password },
            { "scope", scope ?? string.Empty }
        };
    }
}